package com.cloudptt.api.product.pjsua2;

import static org.pjsip.pjsua2.pjmedia_dir.PJMEDIA_DIR_ENCODING;
//import static org.pjsip.pjsua2.pjmedia_vid_dev_std_index.PJMEDIA_VID_DEFAULT_CAPTURE_DEV;
import static org.pjsip.pjsua2.pjsua_call_vid_strm_op.PJSUA_CALL_VID_STRM_ADD;
import static org.pjsip.pjsua2.pjsua_call_vid_strm_op.PJSUA_CALL_VID_STRM_CHANGE_CAP_DEV;
import static org.pjsip.pjsua2.pjsua_call_vid_strm_op.PJSUA_CALL_VID_STRM_REMOVE;
import static org.pjsip.pjsua2.pjsua_call_vid_strm_op.PJSUA_CALL_VID_STRM_SEND_KEYFRAME;
import static org.pjsip.pjsua2.pjsua_call_vid_strm_op.PJSUA_CALL_VID_STRM_START_TRANSMIT;
import static org.pjsip.pjsua2.pjsua_call_vid_strm_op.PJSUA_CALL_VID_STRM_STOP_TRANSMIT;
import static org.pjsip.pjsua2.pjsua_vid_req_keyframe_method.PJSUA_VID_REQ_KEYFRAME_RTCP_PLI;

import android.content.Context;
import android.content.Intent;
import android.graphics.PixelFormat;
import android.opengl.EGL14;
import android.opengl.EGLConfig;
import android.opengl.EGLContext;
import android.opengl.EGLDisplay;
import android.opengl.EGLSurface;
import android.opengl.GLES20;
import android.os.Handler;
import android.os.SystemClock;
import android.view.Surface;
import android.view.SurfaceView;
import android.view.View;

import com.cloudptt.api.comm.CauseCont;
import com.cloudptt.api.models.SipMsgParser;
import com.cloudptt.api.models.call.RtcpMsg;
import com.cloudptt.api.pjsip.api.ImsProfile;
import com.cloudptt.api.pjsip.api.SipCallSession;
import com.cloudptt.api.pjsip.api.SipManager;
import com.cloudptt.api.product.func.call.CallAttr;
import com.cloudptt.api.product.log.Log;
import com.mcptt.config.body.InXml;
import com.mcptt.config.body.ResourceListsBody;
import com.mcptt.config.body.info.mcptt.McpttInfoBody_Conference;
import com.mcptt.config.body.info.mcptt.McpttInfoBody_GCall;
import com.mcptt.config.body.info.mcptt.McpttInfoBody_PCall;
import com.mcptt.config.body.info.mcvideo.McpttvideoBody_PCall;
import com.mcptt.config.body.info.mcvideo.McvideoInfoBody_Conference;
import com.mcptt.config.body.info.mcvideo.McvideoInfoBody_GCall;
import com.mcptt.config.model.ImsInfo;

import org.pjsip.pjsua2.AccountConfig;
import org.pjsip.pjsua2.AudioMedia;
import org.pjsip.pjsua2.BuddyConfig;
import org.pjsip.pjsua2.Call;
import org.pjsip.pjsua2.CallInfo;
import org.pjsip.pjsua2.CallMediaInfo;
import org.pjsip.pjsua2.CallMediaInfoVector;
import org.pjsip.pjsua2.CallOpParam;
import org.pjsip.pjsua2.CallSetting;
import org.pjsip.pjsua2.CallVidSetStreamParam;
import org.pjsip.pjsua2.Media;
import org.pjsip.pjsua2.MediaFormatVideo;
import org.pjsip.pjsua2.OnCallMediaEventParam;
import org.pjsip.pjsua2.OnCallMediaStateParam;
import org.pjsip.pjsua2.OnCallRxOfferParam;
import org.pjsip.pjsua2.OnCallStateParam;
import org.pjsip.pjsua2.OnCallTsxStateParam;
import org.pjsip.pjsua2.OnFloorInfoParam;
import org.pjsip.pjsua2.OnStreamPreCreateParam;
import org.pjsip.pjsua2.SipHeader;
import org.pjsip.pjsua2.SipHeaderVector;
import org.pjsip.pjsua2.VideoPreview;
import org.pjsip.pjsua2.VideoPreviewOpParam;
import org.pjsip.pjsua2.VideoWindow;
import org.pjsip.pjsua2.VideoWindowHandle;
import org.pjsip.pjsua2.pjmedia_dir;
import org.pjsip.pjsua2.pjmedia_event_type;
import org.pjsip.pjsua2.pjmedia_orient;
import org.pjsip.pjsua2.pjmedia_type;
import org.pjsip.pjsua2.pjsip_inv_state;
import org.pjsip.pjsua2.pjsip_status_code;
import org.pjsip.pjsua2.pjsua2;
import org.pjsip.pjsua2.pjsua2JNI;
import org.pjsip.pjsua2.pjsua_call_media_status;
import org.pjsip.pjsua2.pjsua_call_vid_strm_op;

public class MyCall extends Call {
    public static String TAG = "MyCall";
//    public static String EXT_KEY = "X-Info";

    private Context ctx = null;
    private String callIdStr = CallAttr.DEF_CALL_ID_STR;
    private int callType = CallAttr.CallType_Private;
    private int callDir = CallAttr.CallDir_MO;
    public boolean vidPrevStarted;
    public VideoWindow vidWin;
    public VideoPreview vidPrev;
    private SipCallSession session = null;

    private int curCallStatus = pjsip_inv_state.PJSIP_INV_STATE_NULL;
    private CallMediaInfo videoCallMediaInfo = null;
    private CallOpParam prm = null;
    private CallOpParam outPrm = null;

    //    private VideoPreviewOpParam vidPrevParam = null;
//    private VideoWindowHandle vidWH = null;
    private SurfaceView surfacePreview = null;
    private SurfaceView surfaceInVideo = null;

    private VideoSurfaceHandler localVideoHandler;
    private VideoSurfaceHandler remoteVideoHandler;

    //    private CallOpParam outPrm200 = null;
    private MyAccount acc = null;
    private MyBuddy conferenceBuddy  = null;
    private boolean isFront = true;
    private boolean isActiveConference = false;

    public MyCall(Context ctx, MyAccount acc, int call_id)
    {
        super(acc, call_id);
        this.ctx = ctx;
        this.acc = acc;
        this.vidWin = null;
        this.vidPrev = null;
        this.localVideoHandler = null;
        this.remoteVideoHandler = null;
        this.surfacePreview = null;
        this.surfaceInVideo = null;
    }

    public void updateCallInfo(String callIdStr,int callType,int callDir)
    {
        this.callIdStr = callIdStr;
        this.callType = callType;
        this.callDir = callDir;
    }


    public int makeCall(final String callee,final int callType,final boolean isHaveVideo,final boolean isEmergency,String funcNum,String locationStr) throws Exception
    {
        Log.d(TAG, "makeCall callee = " + callee  +  " callType = " + callType +  " isHaveVideo = " + isHaveVideo + " isEmergency = " + isEmergency + " funcNum = " + funcNum);
        prm = new CallOpParam(true);
        CallSetting callSetting = prm.getOpt();
        int mcType = CallAttr.McType_McPtt;
        if(isHaveVideo)
        {
            mcType = CallAttr.McType_McVideo;
            callSetting.setVideoCount(1);
        }
        else {
            callSetting.setVideoCount(0);
        }
        callSetting.setMcType(mcType);
        callSetting.setCallType(callType);
        callSetting.setCalleeNum(callee);

        AccountConfig cfg = acc.accCfg;//.cfg;
        int cap_dev = cfg.getVideoConfig().getDefaultCaptureDevice();
        Log.d(TAG, "makeCall cap_dev = " + cap_dev);

        if(CallAttr.isGroupCall(callType))
        {
            callSetting.setMcxCount(1);
            callSetting.setMcImplicitRequest(true);
            callSetting.setMcQueueing(true);
            callSetting.setMcPriority(5);

            String clientId = acc.getImsProfile().getClientId();
            Log.d(TAG, "makeCall clientId = " + clientId);

            if(mcType == CallAttr.McType_McVideo)
            {
                String selfMcvideoId = acc.getImsProfile().getMcvideoId();
                McvideoInfoBody_GCall infoBody_GCall = new McvideoInfoBody_GCall(callType,callee,selfMcvideoId,clientId,isEmergency,funcNum);
                Log.d(TAG, "makeCall infoBody_GCall = " + infoBody_GCall);
                callSetting.setMcxInfo(infoBody_GCall.toString());
            }
            else
            {
                String selfMcpttId = acc.getImsProfile().getMcpttId();
                McpttInfoBody_GCall infoBody_GCall = new McpttInfoBody_GCall(callType,callee,selfMcpttId,clientId,isEmergency,funcNum);
                Log.d(TAG, "makeCall infoBody_GCall = " + infoBody_GCall);
                callSetting.setMcxInfo(infoBody_GCall.toString());
            }
        }
        else if(CallAttr.isPrivateCall(callType) || CallAttr.isAmbient(callType))
        {
            callSetting.setMcxCount(0);
            callSetting.setMcImplicitRequest(false);
            callSetting.setMcQueueing(false);
            callSetting.setMcPriority(5);
            if(mcType == CallAttr.McType_McVideo)
            {
                McpttvideoBody_PCall infoBody_PCall = new McpttvideoBody_PCall(callType,CallAttr.CallDir_MO,callee,isEmergency,funcNum);
                Log.d(TAG, "makeCall infoBody_PCall = " + infoBody_PCall);
                callSetting.setMcxInfo(infoBody_PCall.toString());
            }
            else
            {
                McpttInfoBody_PCall infoBody_PCall = new McpttInfoBody_PCall(callType,CallAttr.CallDir_MO,callee,isEmergency,funcNum);
                Log.d(TAG, "makeCall infoBody_PCall = " + infoBody_PCall);
                callSetting.setMcxInfo(infoBody_PCall.toString());
            }
            ResourceListsBody resourceListsBody = new ResourceListsBody(callee);
            callSetting.setResourceLists(resourceListsBody.toString());
        }
        Log.d(TAG, "makeCall callSetting.getVideoCount() = " + callSetting.getVideoCount());
        Log.d(TAG, "makeCall locationStr = " + locationStr);
        if(locationStr!= null
                && locationStr.length() > 0)
        {
            callSetting.setLocationInfo(locationStr);
        }

        SipHeaderVector vec = getCallMsgData(callType,mcType);
        prm.getTxOption().setHeaders(vec);
        prm.getOpt().setReqKeyframeMethod(PJSUA_VID_REQ_KEYFRAME_RTCP_PLI);

        session = new SipCallSession();
        session.setCallType(callType);
        session.setHasVideo(isHaveVideo);
        session.setRemoteContact(callee);
        session.setLastReasonCode(0);
        session.setCallState(pjsip_inv_state.PJSIP_INV_STATE_CALLING);

//        buddy_uri = AddrInfo.toSipUrlFromNum(callee);////acc.rewriteNumber(callee);
        makeCall(callee, prm);
        return CauseCont.OperateCheck_Suc;
    }

    private SipHeaderVector getCallMsgData(int callType,int mcType)
    {
        SipHeaderVector vec = new SipHeaderVector();
        String acceptContact1 = "*;+g.3gpp.mcptt;require;explicit";
        String acceptContact2 = "*;+g.3gpp.icsi-ref=\"urn%3Aurn-7%3A3gpp-service.ims.icsi.mcptt\";require;explicit";
        String resourcePriority = "mcpttp.5";
        String pPreferredService = "urn:urn-7:3gpp-service.ims.icsi.mcptt";


        if(mcType == CallAttr.McType_McVideo)
        {
            acceptContact1 = "*;+g.3gpp.mcvideo;require;explicit";
            acceptContact2 = "*;+g.3gpp.icsi-ref=\"urn%3Aurn-7%3A3gpp-service.ims.icsi.mcvideo\";require;explicit";
            resourcePriority = "mcvideop.5";
            pPreferredService = "urn:urn-7:3gpp-service.ims.icsi.mcvideo";

        }
        SipHeader header = new SipHeader();
        header.setHName("Accept-Contact");
        header.setHValue(acceptContact1);
        vec.add(header);

        header = new SipHeader();
        header.setHName("Accept-Contact");
        header.setHValue(acceptContact2);
        vec.add(header);

        header = new SipHeader();
        header.setHName("Resource-Priority");
        header.setHValue(resourcePriority);
        vec.add(header);

        header = new SipHeader();
        header.setHName("P-Preferred-Service");
        header.setHValue(pPreferredService);
        vec.add(header);

        header = new SipHeader();
        header.setHName("P-Preferred-Identity");
        header.setHValue(acc.getImsProfile().getImpuStr());
        vec.add(header);

        String answerMode ="Manual";
        if(CallAttr.isGroupCall(callType))
        {
            header = new SipHeader();
            header.setHName("P-Access-Network-Info");
            header.setHValue("3GPP-E-UTRAN-FDD;utran-cell-id-3gpp=0000000000000000");
            vec.add(header);
            answerMode ="Auto";
        }

        header = new SipHeader();
        header.setHName("Answer-Mode");
        header.setHValue(answerMode);
        vec.add(header);
        return vec;
    }


    public int answer(int code,boolean hasVideo) {
        Log.d(TAG, "answer code = " + code + " hasVideo = " + hasVideo);
        outPrm = new CallOpParam();
        if(code == 180)
        {
            outPrm.setStatusCode(pjsip_status_code.PJSIP_SC_RINGING);
        }
        else {
            outPrm.setStatusCode(pjsip_status_code.PJSIP_SC_OK);
            outPrm.getOpt().setAudioCount(1);

            if(CallAttr.isGroupCall(callType))
            {
                outPrm.getOpt().setMcxCount(1);
                outPrm.getOpt().setMcImplicitRequest(false);
                outPrm.getOpt().setMcQueueing(false);
                outPrm.getOpt().setMcPriority(0);
            }
            Log.d(TAG, "hasVideo = " + hasVideo);
            String selfMcxId = null;
            if (hasVideo
                    && code == 200) {
                outPrm.getOpt().setVideoCount(1);
                outPrm.getOpt().setMcType(CallAttr.McType_McVideo);
                outPrm.getOpt().setReqKeyframeMethod(PJSUA_VID_REQ_KEYFRAME_RTCP_PLI);
                selfMcxId = acc.getImsProfile().getMcvideoId();
                McpttvideoBody_PCall infoBody_PCall = new McpttvideoBody_PCall(callType,CallAttr.CallDir_MT,selfMcxId,false,"");
                outPrm.getOpt().setMcxInfo(infoBody_PCall.toString());
            } else {
                outPrm.getOpt().setVideoCount(0);
                outPrm.getOpt().setMcType(CallAttr.McType_McPtt);
                selfMcxId = acc.getImsProfile().getMcpttId();
                McpttInfoBody_PCall infoBody_PCall = new McpttInfoBody_PCall(callType,CallAttr.CallDir_MT,selfMcxId,false,"");
                outPrm.getOpt().setMcxInfo(infoBody_PCall.toString());
            }
        }
        Log.d(TAG, "answer getVideoCount = " + outPrm.getOpt().getVideoCount());
        AccountConfig cfg = acc.accCfg;//.cfg;
        int cap_dev = cfg.getVideoConfig().getDefaultCaptureDevice();
        Log.d(TAG, "answer cap_dev = " + cap_dev);
        //prm.getOpt().setVideoCount(1);
        //Log.d(TAG,"video count="+prm.getOpt().getVideoCount()+"; audio count="+prm.getOpt().getAudioCount());
        try {
            answer(outPrm);
            return CauseCont.OperateCheck_Suc;
        } catch (Exception e) {
            e.printStackTrace();
            return CauseCont.OperateErr_Exception;
        }
    }



    public int hangup(int code) {
        if(localVideoHandler != null) {
            localVideoHandler.resetVideoWindow();
        }
        if(remoteVideoHandler != null) {
            remoteVideoHandler.resetVideoWindow();
        }

        outPrm = new CallOpParam();
        outPrm.setStatusCode(code);
        try {
            hangup(outPrm);
            return CauseCont.OperateCheck_Suc;
        } catch (Exception e) {
            e.printStackTrace();
            return CauseCont.OperateErr_Exception;
        }
    }

    @Override
    public void onCallState(OnCallStateParam prm) {
//        Log.d(TAG, "onCallState prm = " + prm);
        CallInfo info = null;
        int priority = 0;
        try {
            info = getInfo();
            Log.d(TAG, "onCallState info state:" + info.getState());
            String allMsgStr = prm.getE().getBody().getTsxState().getSrc().getRdata().getWholeMsg();
            Log.d(TAG, "onCallState rx allMsgStr = " + allMsgStr);
            if(allMsgStr.equals(""))
            {
                allMsgStr = prm.getE().getBody().getTsxState().getSrc().getTdata().getWholeMsg();
            }
            Log.d(TAG, "onCallState tx allMsgStr = " + allMsgStr);
            SipMsgParser parser = new SipMsgParser(allMsgStr);
            priority = parser.getPriorityValue();
            Log.d(TAG, "onCallState priority = " + priority);

            curCallStatus = info.getState();
            if (info.getState() == pjsip_inv_state.PJSIP_INV_STATE_CALLING) {
                Log.d(TAG, "onCallState acc = " + acc);
                if(acc != null)
                {
                    String callIdStr = info.getCallIdString();
                    Log.d(TAG, "onCallState callIdStr = " + callIdStr);
                    acc.addMyCall(callIdStr,this);
                }
            }
            else if (info.getState() == pjsip_inv_state.PJSIP_INV_STATE_DISCONNECTED) {
                if(surfacePreview != null)
                {
                    if(localVideoHandler != null) {
                        localVideoHandler.resetVideoWindow();
                        surfacePreview.getHolder().removeCallback(localVideoHandler);
//                            localVideoHandler.setVideoWindow(null);
                        localVideoHandler = null;
                    }
                    surfacePreview.destroyDrawingCache();
                }
                if (vidPrevStarted) {
                    try {
                        vidPrevStarted = false;
                        vidPrev.stop();
                        vidPrev.delete();
                        vidPrev = null;
                    } catch (Exception e) {}
                }
                if(surfaceInVideo != null)
                {
                    if(remoteVideoHandler != null) {
                        remoteVideoHandler.resetVideoWindow();
                        surfaceInVideo.getHolder().removeCallback(remoteVideoHandler);
//                            remoteVideoHandler.setVideoWindow(null);
                        remoteVideoHandler = null;
                    }
                    surfaceInVideo.destroyDrawingCache();
                }
            }
        } catch (Exception e) {
        }
        if (info != null) {
            try {
                if (session != null) {
                    session.updateCallInfo(info);
                }
                if(info.getLastStatusCode() == 403)
                {
                    if(prm !=null
                            && prm.getE() != null
                            && prm.getE().getBody() != null
                            && prm.getE().getBody().getTsxState() != null
                            && prm.getE().getBody().getTsxState().getSrc() != null
                            && prm.getE().getBody().getTsxState().getSrc().getRdata() != null)
                    {
                        String errStr = prm.getE().getBody().getTsxState().getSrc().getRdata().getInfoBody("in+xml");
                        Log.d(TAG, "onCallState errStr = " + errStr);
                        if(errStr != null
                                && errStr.length() > 0) {
                            InXml inXml = InXml.parseXmlStr(errStr);
                            Log.d(TAG, "onCallState inXml = " + inXml);
                            if (inXml != null
                                    && session != null) {
                                String errMsg = inXml.getMsg();
                                String errSubMsg = inXml.getSubMsgDesc();
                                session.setErrMsg(errMsg, errSubMsg);
                            }
                        }
                    }
                }
                Log.d(TAG, "onCallState session = " + session);
                int callType = session.getCallType();
                if (callType != CallAttr.CallType_Prearranged
                        && callType != CallAttr.CallType_Chat)
                {
                    Intent intent = new Intent(SipManager.ACTION_SINGLE_CALL_INFO);
                    intent.putExtra(SipManager.EXTRA_CALL_INFO, session);
//                    intent.putExtra(SipManager.EXTRA_CALL_PRIORITY, priority);
                    if(curCallStatus == pjsip_inv_state.PJSIP_INV_STATE_DISCONNECTED)
                    {
                        ctx.sendBroadcast(intent, SipManager.PERMISSION_USE_SIP);
                    }
                    else
                    {
                        ctx.sendBroadcast(intent, SipManager.PERMISSION_USE_SIP);
                    }
                }
                else
                {
                    Intent intent = new Intent(SipManager.ACTION_SIP_CALL_CHANGED);
                    intent.putExtra(SipManager.EXTRA_CALL_INFO, session);
//                    intent.putExtra(SipManager.EXTRA_CALL_PRIORITY, priority);
                    ctx.sendBroadcast(intent, SipManager.PERMISSION_USE_SIP);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        // Should not delete this call instance (self) in this context,
        // so the observer should manage this call instance deletion
        // out of this callback context.
//        MyApp.observer.notifyCallState(this);
    }

    @Override
    public void onCallTsxState(OnCallTsxStateParam prm) {
        super.onCallTsxState(prm);
    }

    @Override
    public void onCallMediaState(OnCallMediaStateParam prm) {
        Log.d(TAG, "onCallMediaState prm = " + prm);
        SystemClock.sleep(500);
        CallInfo ci;
        try {
            ci = getInfo();
        } catch (Exception e) {
            return;
        }
        curCallStatus = ci.getState();
        Log.d(TAG, "onCallMediaState curCallStatus = " + curCallStatus);

//        if(callType ==  CallAttr.CallType_Prearranged || callType ==  CallAttr.CallType_Chat) {
//            if (curCallStatus != pjsip_inv_state.PJSIP_INV_STATE_CONFIRMED) {
//                return;
//            }
//        }


        CallMediaInfoVector cmiv = ci.getMedia();
        Log.d(TAG, "onCallMediaState cmiv.size() = " + cmiv.size());
        for (int i = 0; i < cmiv.size(); i++) {
            CallMediaInfo cmi = cmiv.get(i);
            Log.d(TAG, "onCallMediaState callMediaInfo type:" + cmi.getType() + "; status:" + cmi.getStatus() + "; IncomingWindowId:" + cmi.getVideoIncomingWindowId());
            if (cmi.getType() == pjmedia_type.PJMEDIA_TYPE_AUDIO &&
                    (cmi.getStatus() == pjsua_call_media_status.PJSUA_CALL_MEDIA_ACTIVE || cmi.getStatus() == pjsua_call_media_status.PJSUA_CALL_MEDIA_LOCAL_HOLD|| cmi.getStatus() == pjsua_call_media_status.PJSUA_CALL_MEDIA_REMOTE_HOLD)) {
                // unfortunately, on Java too, the returned Media cannot be
                // downcasted to AudioMedia
                Log.d(TAG, "onCallMediaState audio is ok");
                Media m = getMedia(i);
                AudioMedia am = AudioMedia.typecastFromMedia(m);
                // connect ports
                try
                {
                    if(CallAttr.isGroupCall(callType)
                            && cmi.getType() == pjmedia_type.PJMEDIA_TYPE_AUDIO
                            && cmiv.size() == 1)//视频组呼需要是全双工
                    {
                        opAudioMedia(0);
                    }
                    else
                    {
                        opAudioMedia(1);
                    }
                    //AudioMedia am = getAudioMedia(i);
                    MyApp.ep.audDevManager().getCaptureDevMedia().
                            startTransmit(am);
                    am.startTransmit(MyApp.ep.audDevManager().
                            getPlaybackDevMedia());

                } catch (Exception e) {
                    Log.d(TAG, "onCallMediaState Failed connecting media ports" + e.getMessage());
                    continue;
                }
            } else if (cmi.getType() == pjmedia_type.PJMEDIA_TYPE_VIDEO &&
                    cmi.getStatus() == pjsua_call_media_status.PJSUA_CALL_MEDIA_ACTIVE  || cmi.getStatus() == pjsua_call_media_status.PJSUA_CALL_MEDIA_LOCAL_HOLD|| cmi.getStatus() == pjsua_call_media_status.PJSUA_CALL_MEDIA_REMOTE_HOLD)
            {
                videoCallMediaInfo = cmi;
                /* If videoPreview was started, stop it first in case capture device has changed */
                Log.d(TAG, "onCallMediaState cmi.getDir() = " + cmi.getDir());
                if ((videoCallMediaInfo.getDir() & PJMEDIA_DIR_ENCODING) != 0)
                {
                    opLocalVideoWin();
                }
                if ((videoCallMediaInfo.getDir() & pjmedia_dir.PJMEDIA_DIR_DECODING) != 0)
                {
                    opRemoteVideoWin();
                }
                Log.d(TAG, "onCallMediaState PJMEDIA_DIR_ENCODING 4");

                try {
                    Log.d(TAG, "onCallMediaState callType = " + callType);
                    if(callType ==  CallAttr.CallType_Prearranged || callType ==  CallAttr.CallType_Chat)
                    {
//                        opVideoMedia(0);
                    }
                    else
                    {
                        opVideoMedia(CallAttr.OpMedia_Resume);
                    }
                }catch (Exception e) {
                    Log.d(TAG, "updateMedia video Failed connecting media ports" + e.getMessage());
                    continue;
                }

//                Log.d(TAG, "onCallMediaState media active, vidWin = "+vidWin+"; vidPrev = "+vidPrev);

                Intent intent = new Intent(SipManager.ACTION_SIP_MEDIA_CHANGED);
                intent.putExtra(SipManager.EXTRA_MEDIA_STATUS, cmi.getStatus());
                String callIdStr = session.getCallIdStr();
                intent.putExtra(SipManager.EXTRA_CALL_ID, callIdStr);
                ctx.sendBroadcast(intent, SipManager.PERMISSION_USE_SIP);
                Log.d(TAG, "onCallMediaState media active, callType = " + callType +"; callDir = " + callDir);
            }
        }
    }
    @Override
    public void onCallMediaEvent(OnCallMediaEventParam prm) {
        Log.d(TAG, "onCallMediaEvent prm.getEv().getType() = " + prm.getEv().getType());
        if (prm.getEv().getType() == pjmedia_event_type.PJMEDIA_EVENT_FMT_CHANGED)
        {

            Intent intent = new Intent(SipManager.ACTION_SIP_VIDEO_EVENT_CHANGED);
            String callIdStr = session.getCallIdStr();
            intent.putExtra(SipManager.EXTRA_CALL_ID, callIdStr);
            ctx.sendBroadcast(intent, SipManager.PERMISSION_USE_SIP);
        }
    }

    public void opVideoMedia(int type) throws java.lang.Exception {
        Log.d(TAG, "opVideoMedia type = " + type);
        CallVidSetStreamParam param = new CallVidSetStreamParam();
//        param.setCapDev(PJMEDIA_VID_DEFAULT_CAPTURE_DEV);
        int cameraId = isFront? 1 :2;
        Log.d(TAG, "opVideoMedia init cameraId = " + cameraId);
        param.setCapDev(cameraId);
        param.setDir(PJMEDIA_DIR_ENCODING);
        int idx = this.vidGetStreamIdx();
        Log.d(TAG, "opVideoMedia idx = " + idx);
        param.setMedIdx(idx);

        if (type == CallAttr.OpMedia_Resume)
        {
            vidSetStream(PJSUA_CALL_VID_STRM_START_TRANSMIT, param);
        }
        else
        {
            vidSetStream(PJSUA_CALL_VID_STRM_STOP_TRANSMIT, param);
        }
    }

    public void opVideoStream(int type) throws java.lang.Exception
    {
        Log.d(TAG, "opVideoStream type = " + type);
        CallVidSetStreamParam param = new CallVidSetStreamParam();
//        param.setCapDev(PJMEDIA_VID_DEFAULT_CAPTURE_DEV);
        int cameraId = isFront? 1 :2;
        Log.d(TAG, "opVideoMedia init cameraId = " + cameraId);
        param.setCapDev(cameraId);
        param.setDir(PJMEDIA_DIR_ENCODING);
        int idx = this.vidGetStreamIdx();
        Log.d(TAG, "opVideoMedia idx = " + idx);
        param.setMedIdx(idx);
        if (type == CallAttr.OpMedia_Add)
        {

//            vidSetStream(PJSUA_CALL_VID_STRM_ADD, param);
            Log.d(TAG, "opVideoMedia PJSUA_CALL_VID_STRM_ADD end ");
        }
        else
        {
            vidPrev.stop();
//            vidSetStream(PJSUA_CALL_VID_STRM_REMOVE, param);
            Log.d(TAG, "opVideoMedia PJSUA_CALL_VID_STRM_REMOVE end ");
        }
    }

    public void switchCamera() throws java.lang.Exception {
        Log.d(TAG, "switchCamera isFront = " + isFront);
        isFront = !isFront;
        int cameraId = isFront? 1 :2;
        CallVidSetStreamParam callVidSetStreamParam = new CallVidSetStreamParam();
        callVidSetStreamParam.setCapDev(cameraId);
        try {
            vidSetStream(pjsua_call_vid_strm_op.PJSUA_CALL_VID_STRM_CHANGE_CAP_DEV, callVidSetStreamParam);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void sendKeyFrame() {
        try {
            Log.d(TAG, "sendKeyFrame");
            CallVidSetStreamParam param = new CallVidSetStreamParam();
//            param.setCapDev(PJMEDIA_VID_DEFAULT_CAPTURE_DEV);
            int cameraId = isFront? 1 :2;
            Log.d(TAG, "sendKeyFrame init cameraId = " + cameraId);
            param.setCapDev(cameraId);
            param.setDir(PJMEDIA_DIR_ENCODING);
            int idx = this.vidGetStreamIdx();
            Log.d(TAG, "sendKeyFrame idx = " + idx);
            param.setMedIdx(idx);

            vidSetStream(PJSUA_CALL_VID_STRM_SEND_KEYFRAME, param);
        }
        catch (Exception e)
        {
            e.printStackTrace();
            Log.d(TAG, "sendKeyFrame e = " + e);
        }
    }

    public void opVideoWinShow(boolean isLocal,boolean isShow)
    {
        Log.d(TAG, "opVideoWinShow isLocal = " + isLocal + " isShow = " + isShow);
        try
        {
            if(isLocal)
            {
                if(isShow)
                {
                    VideoPreviewOpParam param = new VideoPreviewOpParam();
                    MediaFormatVideo format = new MediaFormatVideo();
                    format.setHeight(640);
                    format.setWidth(480);
                    param.setFormat(format);
                    vidPrev.start(param);
                }
                else
                {
                    vidPrev.stop();
                }
                localVideoHandler.setVideoWindow(vidPrev.getVideoWindow());

            }
            else
            {
                if(vidWin != null) {
                    vidWin.Show(isShow);
                }
                remoteVideoHandler.resetVideoWindow();
            }
        }catch (Exception e)
        {
            e.printStackTrace();
            Log.d(TAG, "opVideoWinShow e = " + e);
        }
    }

    private void clearSurface(Surface surface) {
        EGLDisplay display = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);
        int[] version = new int[2];
        EGL14.eglInitialize(display, version, 0, version, 1);

        int[] attribList = {
                EGL14.EGL_RED_SIZE, 8,
                EGL14.EGL_GREEN_SIZE, 8,
                EGL14.EGL_BLUE_SIZE, 8,
                EGL14.EGL_ALPHA_SIZE, 8,
                EGL14.EGL_RENDERABLE_TYPE, EGL14.EGL_OPENGL_ES2_BIT,
                EGL14.EGL_NONE, 0,
                EGL14.EGL_NONE
        };
        EGLConfig[] configs = new EGLConfig[1];
        int[] numConfigs = new int[1];
        EGL14.eglChooseConfig(display, attribList, 0, configs, 0, configs.length, numConfigs, 0);

        EGLConfig config = configs[0];
        EGLContext context = EGL14.eglCreateContext(display, config, EGL14.EGL_NO_CONTEXT, new int[]{
                EGL14.EGL_CONTEXT_CLIENT_VERSION, 2,
                EGL14.EGL_NONE
        }, 0);

        EGLSurface eglSurface = EGL14.eglCreateWindowSurface(display, config, surface,
                new int[]{
                        EGL14.EGL_NONE
                }, 0);

        EGL14.eglMakeCurrent(display, eglSurface, eglSurface, context);
        GLES20.glClearColor(0, 0, 0, 1);
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
        EGL14.eglSwapBuffers(display, eglSurface);
        EGL14.eglDestroySurface(display, eglSurface);
        EGL14.eglMakeCurrent(display, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_CONTEXT);
        EGL14.eglDestroyContext(display, context);
        EGL14.eglTerminate(display);
    }

    public void opLocalVideoWin()
    {
        Log.d(TAG, "opLocalVideoWin vidPrevStarted = " + vidPrevStarted);
        if (vidPrevStarted) {
            try {
                Log.d(TAG, "opLocalVideoWin clear begin");
                vidPrevStarted = false;
                vidPrev.stop();
                vidPrev.delete();
                vidPrev = null;
                Log.d(TAG, "opLocalVideoWin clear end");
            } catch (Exception e) {}
        }
        Log.d(TAG, "opLocalVideoWin surfacePreview is null = " + (surfacePreview != null));
        if (!vidPrevStarted
                && surfacePreview != null)
        {
            try
            {
                this.localVideoHandler = new VideoSurfaceHandler(surfacePreview.getHolder());
                this.surfacePreview.getHolder().addCallback(localVideoHandler);

                int cameraId = isFront? 1 :2;
                Log.d(TAG, "opLocalVideoWin init cameraId = " + cameraId);
                vidPrev = new VideoPreview(cameraId);
                VideoPreviewOpParam param = new VideoPreviewOpParam();
                if(callType ==  CallAttr.CallType_Prearranged || callType ==  CallAttr.CallType_Chat)
                {
                    vidPrev.stop();
                }
                else
                {
                    vidPrev.start(param);
                }
                vidPrevStarted = true;
                Log.d(TAG, "opLocalVideoWin init setVideoWindow 1");
                if (vidPrev != null) {
                    localVideoHandler.setVideoWindow(vidPrev.getVideoWindow());
                }
                Log.d(TAG, "opLocalVideoWin init setVideoWindow 2");
            } catch (Exception e) {
                e.printStackTrace();
                Log.d(TAG,"Failed start video preview" +
                        e.getMessage());
            }
        }
    }
    public void opRemoteVideoWin()
    {
        int winId = videoCallMediaInfo.getVideoIncomingWindowId();
        Log.d(TAG, "opRemoteVideoWin winId = " + winId);
        if(surfaceInVideo != null) {
            Log.d(TAG, "opRemoteVideoWin 1");
//            this.remoteVideoHandler = new VideoSurfaceHandler(surfaceInVideo.getHolder());
//            this.surfaceInVideo.getHolder().addCallback(remoteVideoHandler);
            Log.d(TAG, "opRemoteVideoWin 2");
            if (winId != pjsua2.INVALID_ID) {
                vidWin = new VideoWindow(winId);
            }
            Log.d(TAG, "opRemoteVideoWin 3");
            this.remoteVideoHandler = new VideoSurfaceHandler(surfaceInVideo.getHolder());
            if (remoteVideoHandler != null) {
                VideoWindow vw = videoCallMediaInfo.getVideoWindow();
                remoteVideoHandler.setVideoWindow(vw);
            }
        }
    }

    public void setSufaceView(SurfaceView surfaceInVideo,SurfaceView surfacePreview)
    {
        Log.d(TAG, "setSufaceView");
        this.surfacePreview = surfacePreview;
        this.surfaceInVideo = surfaceInVideo;
    }

    public void onFloorEvent(OnFloorInfoParam prm)
    {
        Log.d(TAG, "onFloorEvent prm = " + prm);
        if(prm != null)
        {
            String floorInfo = prm.getRtcpMsg();
            Log.d(TAG, "onFloorEvent floorInfo = " + floorInfo);
            String callIdStr = CallAttr.DEF_CALL_ID_STR;
            CallInfo info = null;
            try {
                info = getInfo();
                callIdStr = info.getCallIdString();
            }
            catch (Exception e)
            {
                e.printStackTrace();
                return;
            }

            Intent callStateChangedIntent = new Intent(
                    SipManager.ACTION_SIP_SPEAKING_CHANGED);
            callStateChangedIntent.putExtra(SipManager.EXTRA_CALL_ID, callIdStr);
            callStateChangedIntent.putExtra(SipManager.EXTRA_SPEAKING_INFO, floorInfo);
            ctx.sendBroadcast(callStateChangedIntent,
                    SipManager.PERMISSION_USE_SIP);
        }
    }

    public SipCallSession getSession() {
        return session;
    }

    public void setSession(SipCallSession session) {
        this.session = session;
    }

    public int subcribeConference(boolean isActive, String sessionId,String groupNum,boolean hasVideo)
    {
        Log.d(TAG, "subcribeConference isActive = " + isActive +  " sessionId = " + sessionId + " groupNum = " + groupNum + " hasVideo = " + hasVideo);
        try {
            if(isActiveConference == isActive)
            {
                return CauseCont.OperateCheck_Suc;
            }
            isActiveConference = isActive;
            String idStr = acc.getImsProfile().getImpuStr();
            if(isActive)
            {
                initConferenceBuddy(sessionId,hasVideo);
                if(conferenceBuddy != null) {
                    String conferenceXml ="";
                    if(hasVideo)
                    {
                        McvideoInfoBody_Conference body = new McvideoInfoBody_Conference(groupNum);
                        conferenceXml = body.toString();
                        Log.d(TAG, "subcribeConference conferenceXml = " + conferenceXml);
                    }
                    else
                    {
                        McpttInfoBody_Conference body = new McpttInfoBody_Conference(groupNum);
                        conferenceXml = body.toString();
                        Log.d(TAG, "subcribeConference conferenceXml = " + conferenceXml);
                    }

                    conferenceBuddy.subscribeConference(isActive,idStr,conferenceXml);
                }
            }
            else
            {
                conferenceBuddy.subscribeConference(false,idStr,"");
            }

        }catch (Exception e)
        {
            Log.d(TAG, "subcribeFunc e2 = " + e);
            e.printStackTrace();
        }
        return CauseCont.OperateCheck_Suc;
    }
    private void initConferenceBuddy(String sipUrl,boolean hasVideo)
    {
        delBuddy();
        BuddyConfig cfg = new BuddyConfig();
        Log.d(TAG, "initConferenceBuddy sipUrl = " + sipUrl);
        cfg.setUri(sipUrl);
        cfg.setAccId(this.acc.getId());
        cfg.setMcType(CallAttr.McType_McPtt);
        if(hasVideo)
        {
            cfg.setMcType(CallAttr.McType_McVideo);
        }
        cfg.setSubscribe(true);
        conferenceBuddy = new MyBuddy(cfg);
        try {
            conferenceBuddy.create(acc, cfg);
        } catch (Exception e) {
            Log.d(TAG, "initMcdataBuddy e1 = " + e);
            conferenceBuddy.delete();
            conferenceBuddy = null;
        }
    }
    private void delBuddy()
    {
        if(conferenceBuddy != null) {
            conferenceBuddy.delete();
            conferenceBuddy = null;
        }
    }
    public void clean()
    {
        delBuddy();
        this.vidWin = null;
        this.vidPrev = null;
        localVideoHandler = null;
        remoteVideoHandler = null;
        surfacePreview = null;
        surfaceInVideo = null;
    }
    public void onStreamPreCreate(OnStreamPreCreateParam prm)
    {
        Log.d(TAG, "onStreamPreCreate");
    }
}
